// License: Attribution 4.0 International (CC BY 4.0)
/*--- __ECO__ __PLAYMAKER__ __ACTION__ ---*/
//  v1.0.1 for UNITY 5.2+
// Keywords: Sound

using UnityEngine;
using HutongGames.PlayMaker;
using UnityEngine.Audio;

namespace HutongGames.PlayMaker.Actions
{
	
	[ActionCategory(ActionCategory.Audio)]
	[Tooltip("Advance Audio Clip player. 3d position defined by a Game Object or Vector3. If a Vector3 position is defined, it takes priority over the game object. Set Audio Source component on a Game Object. Optionally plays a one shot Audio Clip with Audio Source settings.")]
	[HelpUrl("http://hutonggames.com/playmakerforum/index.php?topic=11596.0")]
	public class PlayAudioAdvance : FsmStateAction
	{
		
		
		[ActionSection("Obj Setup")]
		
		public FsmOwnerDefault gameObject;
		
		[ActionSection("One Shot Vector3 Setup")]
		
		public FsmVector3 vector3;
		[Tooltip("Use local or world space.")]
		public Space space;
		[TitleAttribute("Disable position")]
		public FsmBool disable;
		
		[ActionSection("Audio Setup")]
		
		[RequiredField]
		[Title("Audio Clip")]
		[ObjectType(typeof(AudioClip))]
		[Tooltip("Optionally play a 'one shot' AudioClip. NOTE: Volume cannot be adjusted while playing a 'one shot' AudioClip.")]
		public FsmObject clip;
		[Tooltip("Plays a one shot Audio Clip.")]
		public FsmBool oneShot;
		
		[ActionSection("Volume")]
		[HasFloatSlider(0, 1)]
		public FsmFloat volume;
		
		[ActionSection("General Options")]

		[Tooltip("0.0 makes the sound full 2D, 1.0 makes it full 3D")]
		public FsmFloat spatialBlend;
		public FsmBool SpatialBlendCurve;
		public FsmAnimationCurve spatialBlendCurve;
		[Tooltip("Allows AudioSource to play even though AudioListener.pause is set to true. This is useful for the menu element sounds or background music in pause menus.")]
		public FsmBool ignoreListenerPause;
		[Tooltip("Allows AudioSource to play even though AudioListener.pause is set to true. This is useful for the menu element sounds or background music in pause menus.")]
		public FsmBool ignoreListenerVolume;
		public FsmBool playOnAwake;
		public FsmBool loop;
		[Tooltip("Enables or disables spatialization.")]
		public FsmBool spatialize;
		[Tooltip("Pans a playing sound in a stereo way (left or right). This only applies to sounds that are Mono or Stereo. / -1.0 = Full left / 0.0 = center / 1.0 = full right")]
		[HasFloatSlider(-1.0f, 1f)]
		public FsmFloat panStereo;
		
		[ActionSection("Mixer Options")]
		public FsmObject mixer;
		
		
		[ActionSection("3D Options")]
		
		[Tooltip("Sets the Doppler scale for this AudioSource.")]
		public FsmFloat dopplerLevel;
		[Tooltip("Sets the spread angle (in degrees) of a 3d stereo or multichannel sound in speaker space.0 = all sound channels are located at the same speaker location and is 'mono'. 360 = all subchannels are located at the opposite speaker location to the speaker location that it should be according to 3D position. Default = 0.")]
		[HasFloatSlider(0f, 360f)]
		public FsmBool useSpread;
		public FsmFloat spread;
		public FsmBool spreadCurve;
		public FsmAnimationCurve SpreadCurve;
		[Tooltip("Sets/Gets how the AudioSource attenuates over distance.")]
		public AudioRollOffmode rolloffMode;
		public enum AudioRollOffmode {Off, Linear, Logarithmic, custom};
		[Tooltip("Only works if custom is selected!")]
		public FsmAnimationCurve rolloffCurve;
		[Tooltip("MaxDistance the distance the AudioSource will cease to grow louder in volume.")]
		public FsmFloat minDistance;
		[Tooltip("MaxDistance is the distance a sound stops attenuating at")]
		public FsmFloat maxDistance;
		
		[ActionSection("Audio priority")]
		
		[Tooltip("when there's more AudioSources playing than available hardware channels. The AudioSources with lowest priority (and audibility) is virtualized first. Priority is an integer between 0 and 255. 0=highest priority, 255=lowest priority.")]
		public FsmBool usePriority;
		public FsmInt priority;
		
		[ActionSection("Physics")]
		public VelocityupdateMode velocityUpdateSelect;
		public enum VelocityupdateMode { Off, Dynamic, Fixed};
		
		[ActionSection("Pitch")]
		public FsmBool usePitch;
		public FsmInt startingPitch;
		public FsmInt timeToDecrease;
		
		[ActionSection("Filters")]
		[Tooltip("Bypass effects (Applied from filter components or global listener filters)")]
		public FsmBool bypassEffects;
		[Tooltip("When set global effects on the AudioListener will not be applied to the audio signal generated by the AudioSource. Does not apply if the AudioSource is playing into a mixer group")]
		public FsmBool bypassListenerEffects;
		[Tooltip("When set doesn't route the signal from an AudioSource into the global reverb associated with reverb zones.")]
		public FsmBool bypassReverbZones;
		[Tooltip("The amount by which the signal from the AudioSource will be mixed into the global reverb associated with the Reverb Zones. The range from 0 to 1 is linear (like the volume property) while the range from 1 to 1.1 is an extra boost range that allows you to boost the reverberated signal by 10 dB. ")]
		[HasFloatSlider(0f, 1.1f)]
		public FsmFloat reverbZoneMix;
		public FsmBool ReverbZoneMixCurve;
		public FsmAnimationCurve reverbZoneMixCurve;

		
		[ActionSection("Events")]
		public FsmEvent finishEvent;
		
		[ActionSection("Debug Options")]
		
		public FsmBool debugChannel;
		public FsmBool debugFrequency;
		
		
		
		private AudioSource audio;
		private GameObject go;
		private bool audioClipLengthTemp;
		private Vector3 position;
		private AudioSource audioSourceOneShot;
		GameObject AudioOneShot;
		private AudioMixerGroup mixerGroup;
		
		public override void Reset()
		{
			gameObject = null;
			vector3 = new FsmVector3 { UseVariable = true };
			space = Space.Self;
			disable = false;
			clip = null;
			playOnAwake = true;
			loop = false;
			oneShot = false;
			volume = 1f;
			spreadCurve = false;
			bypassEffects = false;
			SpatialBlendCurve = false;
			spatialBlend = 1;
			ignoreListenerPause = false;
			usePriority = false;
			spatialize = false;
			mixer = null;
			ReverbZoneMixCurve = false;
			panStereo = 0.0f;
			maxDistance = 0.0f;
			minDistance = 0.0f;
			useSpread = false;
			spread = 0.0f;
			rolloffMode = AudioRollOffmode.Off;
			usePriority = false;
			priority = 0;
			velocityUpdateSelect = VelocityupdateMode.Off;
			usePitch = false;
			startingPitch = 4;
			timeToDecrease = 5;
			bypassListenerEffects = false;
			bypassReverbZones = false;
			dopplerLevel = 1;
			reverbZoneMix = 1;
			ignoreListenerVolume = false;
			finishEvent = null;
			debugChannel = false;

		}
		
		public override void OnEnter()
		{
			
			go = Fsm.GetOwnerDefaultTarget(gameObject);
			
			if (disable.Value == false)
				posSetup();

			
			if (spatialBlend.Value < 0 || spatialBlend.Value > 1){
				spatialBlend.Value = 1;
				Debug.LogWarning("spatialBlend error. Needs to be between 0 to 1");
			}

			
			if (oneShot.IsNone || oneShot.Value == false){
				audio = go.GetComponent<AudioSource>();
				
				if (clip.Value != null)
					audio.clip = clip.Value as AudioClip;
				
				if (audio == null)
					audio = AudioOneShot.AddComponent<AudioSource>();
				audio.clip = clip.Value as AudioClip;

				goDebug();
				Setup();
				DoPlaySound();
			}
			
			else {
				goDebug();
				oneShotSetup();
				Setup();
				audioSourceOneShot.Play();
				
				if (oneShot.Value == true){
					oneShotUpdate();
				}
				
			}
			
		}
		
		void posSetup(){
			
			if (vector3.IsNone)
			{
				position = space == Space.World ? go.transform.position : go.transform.localPosition;
				
			}
			
			else
			{
				position = vector3.Value;
				
			}

			
			return;
			
		}
		
		
		void DoPlaySound()
		{
			
			audio.Play();
			
			if (usePitch.Value == false)
			{
				Fsm.Event(finishEvent);
				Finish();
			}
			
		}
		
		public override void OnUpdate() {


			if (usePitch.Value == true){
				if (audio.pitch > 0)
					audio.pitch -= Time.deltaTime * startingPitch.Value / timeToDecrease.Value;
			}
		
			
			if (audio == null)
			{
				Fsm.Event(finishEvent);
				Finish();
			}
			
			AudioUpdate();
			
		}
		
		void oneShotUpdate()
		{
			if (oneShot.Value)
			{
				Fsm.Event(finishEvent);
				Finish();
			}
		}
		
		void AudioUpdate()
		{
			
			if (!audio.isPlaying || audio.clip.length <= 0.0f )
			{
				Fsm.Event(finishEvent);
				Finish();
			}
			else if (!volume.IsNone)
			{
				audio.volume = volume.Value;
				
			}

			
			return;
		}
		
		void Setup(){
			
			if (mixer.Value !=null)
				audio.outputAudioMixerGroup = mixer.Value as AudioMixerGroup;
			
			if (SpatialBlendCurve.Value == false){
				audio.spatialBlend = spatialBlend.Value;
			}
			else {
				
				audio.SetCustomCurve(AudioSourceCurveType.SpatialBlend, spatialBlendCurve.curve);
				
			}
			
			audio.volume = volume.Value;
			audio.bypassEffects = bypassEffects.Value;
			audio.bypassListenerEffects = bypassListenerEffects.Value;
			
			if (ReverbZoneMixCurve.Value == false & bypassReverbZones.Value == true){
				audio.bypassReverbZones = bypassReverbZones.Value;
			}
			
			if (ReverbZoneMixCurve.Value == true & bypassReverbZones.Value == true){
				
				audio.SetCustomCurve(AudioSourceCurveType.ReverbZoneMix, reverbZoneMixCurve.curve);
				
			}
			
			
			audio.dopplerLevel = dopplerLevel.Value;
			audio.ignoreListenerPause = ignoreListenerPause.Value;
			audio.ignoreListenerVolume = ignoreListenerVolume.Value;
			audio.panStereo = panStereo.Value;
			audio.loop = loop.Value;
			audio.playOnAwake = playOnAwake.Value;
			audio.reverbZoneMix = reverbZoneMix.Value;
			audio.spatialize = spatialize.Value;
			
			if (usePriority.Value == true)
				audio.priority = priority.Value;
			
			if (useSpread.Value == true & spreadCurve.Value == false)
			{
				audio.spread = spread.Value;
			}
			
			if (useSpread.Value == true & spreadCurve.Value == true)
			{
				audio.SetCustomCurve(AudioSourceCurveType.Spread, SpreadCurve.curve);
			}
			
			if (rolloffMode == AudioRollOffmode.Off){
				//off
			}
			else {
				if (rolloffMode == AudioRollOffmode.Linear){
					audio.rolloffMode = AudioRolloffMode.Linear;
					audio.minDistance = minDistance.Value;
					audio.maxDistance = maxDistance.Value;}
				
				if (rolloffMode == AudioRollOffmode.Logarithmic){
					audio.rolloffMode = AudioRolloffMode.Logarithmic;
					audio.minDistance = minDistance.Value;
					audio.maxDistance = maxDistance.Value;}
				
				if (rolloffMode == AudioRollOffmode.custom){
					audio.rolloffMode = AudioRolloffMode.Custom;
					audio.SetCustomCurve(AudioSourceCurveType.CustomRolloff, rolloffCurve.curve);
				}
			}
			
			
			if (velocityUpdateSelect == VelocityupdateMode.Off){
				//off
			}
			
			else{
				if (velocityUpdateSelect == VelocityupdateMode.Dynamic){
					audio.velocityUpdateMode = AudioVelocityUpdateMode.Dynamic;
					
				}
				if (velocityUpdateSelect == VelocityupdateMode.Fixed){
					audio.velocityUpdateMode = AudioVelocityUpdateMode.Fixed;
					
					
				}
			}
			

			
			
			return;
		}
		
		
		void oneShotSetup()
			
		{
			AudioOneShot = new GameObject("Audio_OneShot");
			AudioOneShot.transform.position = position;
			audioSourceOneShot = AudioOneShot.AddComponent<AudioSource>();
			audioSourceOneShot.clip = clip.Value as AudioClip;
			audio = audioSourceOneShot;
			MonoBehaviour.Destroy(AudioOneShot,audioSourceOneShot.clip.length);
			
			return;
		}
		
		void goDebug(){
			
			
			if (debugChannel.Value){
				int channel = audio.clip.channels;
				Debug.Log (audio.name+" Channels: "+channel);
			}
			
			
			if (debugFrequency.Value){
				int freq = audio.clip.frequency;
				Debug.Log (audio.name+" Frequency: "+freq);
			}
			return;
			
		}
	}
	
}

